package cn.aitrox.ry.service.anno.mq.consumer;

import cn.aitrox.ry.bean.RespResult;
import cn.aitrox.ry.common.bean.JsonCallback;
import cn.aitrox.ry.constant.CommonConstant;
import cn.aitrox.ry.service.anno.config.AnnoNacosProperties;
import cn.aitrox.ry.service.anno.dao.AnnoLesionResultDao;
import cn.aitrox.ry.service.anno.dao.AnnoLesionResultDetailDao;
import cn.aitrox.ry.service.anno.dao.AnnoResultDao;
import cn.aitrox.ry.service.anno.entity.AnnoLesionResultDetailEntity;
import cn.aitrox.ry.service.anno.entity.AnnoLesionResultEntity;
import cn.aitrox.ry.service.anno.entity.AnnoResultEntity;
import cn.aitrox.ry.service.anno.mq.msg.Mask2NiiMsg;
import cn.aitrox.ry.service.anno.remote.imageService.ImageServiceApi;
import cn.aitrox.ry.service.anno.remote.imageService.ImageServiceMethodEnum;
import cn.aitrox.ry.service.anno.remote.imageService.dto.ImageServiceRespDto;
import cn.aitrox.ry.service.anno.remote.imageService.dto.mask2Nii.Mask2NiiReqDataDto;
import cn.aitrox.ry.service.anno.remote.imageService.dto.mask2Nii.Mask2NiiRespDataDto;
import cn.aitrox.ry.service.dwh.dto.DwhImageDto;
import cn.aitrox.ry.service.dwh.dto.DwhSeriesDto;
import cn.aitrox.ry.service.dwh.dto.in.DwhImageQueryInDto;
import cn.aitrox.ry.service.dwh.dto.in.DwhSeriesQueryInDto;
import cn.aitrox.ry.service.dwh.feign.DwhImageFeign;
import cn.aitrox.ry.service.dwh.feign.DwhSeriesFeign;
import cn.aitrox.ry.service.oss.feign.OssFeign;
import cn.aitrox.ry.util.ArrayUtil;
import cn.aitrox.ry.util.DateUtil;
import cn.aitrox.ry.util.FsUtil;
import cn.aitrox.ry.util.JSONUtil;
import cn.aitrox.ry.util.JacksonUtil;
import cn.aitrox.ry.util.LogUtil;
import cn.aitrox.ry.util.UUIDUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.activemq.command.ActiveMQTextMessage;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import javax.jms.Message;
import javax.jms.MessageListener;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Component
public class Mask2niiConsumer implements MessageListener {

    private static final Logger LOG = LoggerFactory.getLogger(Mask2niiConsumer.class);

    @Autowired
    private ImageServiceApi imageServiceApi;

    @Autowired
    private AnnoLesionResultDetailDao annoLesionResultDetailDao;

    @Autowired
    private AnnoLesionResultDao annoLesionResultDao;

    @Autowired
    private AnnoResultDao annoResultDao;

    @Lazy
    @Autowired
    private DwhImageFeign dwhImageFeign;

    @Lazy
    @Autowired
    DwhSeriesFeign dwhSeriesFeign;

    @Lazy
    @Autowired
    private OssFeign ossFeign;

    @Autowired
    private AnnoNacosProperties annoNacosProperties;


    @Override
    public void onMessage(Message message) {
        String msg = CommonConstant.EMPTY;
        String destPath = StringUtils.joinWith(File.separator, annoNacosProperties.getShareDataPath(), "tmp", "mask2nii", UUIDUtil.getUUID());
        String coordFileParentPath = StringUtils.joinWith(File.separator, destPath, "coord");
        try {
            ActiveMQTextMessage textMessage = (ActiveMQTextMessage) message;
            msg = textMessage.getText();
            LOG.info(LogUtil.gen("Mask2niiConsumer receive", "msg", msg));
            Mask2NiiMsg mask2NiiMsg = JSONUtil.fromJson(msg, Mask2NiiMsg.class);
            Integer alrId = mask2NiiMsg.getAlrId();

            // 查询病灶结果，判断如果nii文件已生成，不再重复生成
            AnnoLesionResultEntity annoLesionResultEntity = annoLesionResultDao.findById(alrId);
            if (null == annoLesionResultEntity) {
                LOG.error(LogUtil.gen("Mask2niiConsumer 病灶结果不存在", "alrd", alrId + ""));
                return;
            }

            AnnoResultEntity annoResultEntity = annoResultDao.findById(annoLesionResultEntity.getArId());

            if (null == annoResultEntity) {
                LOG.info(LogUtil.gen("Mask2niiConsumer 标注结果不存在", "alrd", alrId + ""));
                return;
            }

            if (StringUtils.isNotEmpty(annoLesionResultEntity.getMaskFilePath())) {
                LOG.info(LogUtil.gen("Mask2niiConsumer NII结果已存在", "alrd", alrId + ""));
                return;
            }

            List<AnnoLesionResultDetailEntity> lesionResultDetailList = annoLesionResultDetailDao.findByAlrIds(Arrays.asList(alrId));

            if (ArrayUtil.isEmpty(lesionResultDetailList)) {
                LOG.error(LogUtil.gen("Mask2niiConsumer 病灶mask结果不存在", "alrd", alrId + ""));
                return;
            }

            RespResult<List<DwhSeriesDto>> seriesRespResult = dwhSeriesFeign.seriesQuery(new DwhSeriesQueryInDto(Arrays.asList(annoResultEntity.getSeriesUid())));
            if (!seriesRespResult._isOk()) {
                LOG.error(LogUtil.gen("Mask2niiConsumer 查询数仓序列详情失败", "seriesUid", annoResultEntity.getSeriesUid()));
                return;
            }
            List<DwhSeriesDto> seriesList = seriesRespResult.getData();
            if (ArrayUtil.isEmpty(seriesList)) {
                LOG.error(LogUtil.gen("Mask2niiConsumer 查询数仓序列详情无结果", "seriesUid", annoResultEntity.getSeriesUid()));
                return;
            }

            // 查询数仓Image
            RespResult<Map<String, List<DwhImageDto>>> imageRespResult = dwhImageFeign.imageQuery(new DwhImageQueryInDto(Arrays.asList(annoResultEntity.getSeriesUid())));
            if (!imageRespResult._isOk()) {
                LOG.error(LogUtil.gen("Mask2niiConsumer 查询数仓序列影像失败", "seriesUid", annoResultEntity.getSeriesUid()));
                return;
            }
            List<DwhImageDto> imageList = imageRespResult.getData().get(annoResultEntity.getSeriesUid());
            if (ArrayUtil.isEmpty(imageList)) {
                LOG.error(LogUtil.gen("Mask2niiConsumer 查询数仓序列影像无结果", "seriesUid", annoResultEntity.getSeriesUid()));
                return;
            }

            // 将每一层的点位写入到临时文件
            this.maskCoord2File(coordFileParentPath, lesionResultDetailList);

            String rows = seriesList.get(0).getRows();
            String columns = seriesList.get(0).getColumns();
            Integer maxInstanceNumber = imageList.stream().map(DwhImageDto::getNumber).sorted(Comparator.reverseOrder()).findFirst().orElse(null);

            Mask2NiiReqDataDto mask2NiiReqDataDto = new Mask2NiiReqDataDto(annoResultEntity.getSeriesUid(), Integer.parseInt(rows), Integer.parseInt(columns), maxInstanceNumber, destPath, coordFileParentPath);

            // 调用nii转换
            ImageServiceRespDto<Mask2NiiRespDataDto> respDto = imageServiceApi.doRequest(mask2NiiReqDataDto, ImageServiceMethodEnum.MASK_2_NII, new JsonCallback<ImageServiceRespDto<Mask2NiiRespDataDto>>() {
                @Override
                public ImageServiceRespDto<Mask2NiiRespDataDto> deserializer(String json) throws IOException {
                    ImageServiceRespDto<Mask2NiiRespDataDto> imageServiceRespDto = JacksonUtil.Json2Obj(json, new TypeReference<ImageServiceRespDto<Mask2NiiRespDataDto>>() {
                    });
                    return imageServiceRespDto;
                }
            });

            if (!respDto._isOk()) {
                LOG.error(LogUtil.gen("Mask2niiConsumer 请求影像服务生成NII失败", "errMsg", respDto.getMsg() + "", "msg", msg));
                return;
            }

            // 上传nii到oss
            String maskKey = this.genMaskOssPath(annoResultEntity.getTaskId(), "mask.nii.gz");
            ossFeign.putLocal(maskKey, respDto.getData().getNiiPath(), annoNacosProperties.getOssType());

            // 更新nii在oss中的key到病灶表中
            annoLesionResultDao.updateMaskPath(alrId, maskKey);

            LOG.info(LogUtil.gen("Mask2niiConsumer success", "msg", msg));
        } catch (Exception e) {
            LOG.error(LogUtil.genException(e, "Mask2niiConsumer error", "msg", msg), e);
        } finally {
            // 删除临时文件
            FsUtil.deleteDir(destPath);
        }
    }

    private void maskCoord2File(String coordFileParentPath, List<AnnoLesionResultDetailEntity> lesionResultDetailList) throws IOException {
        FsUtil.ensureDirExist(new File(coordFileParentPath));
        for (AnnoLesionResultDetailEntity annoLesionResultDetail : lesionResultDetailList) {
            Integer layer = annoLesionResultDetail.getLayer();
            String result = annoLesionResultDetail.getResult();
            FileWriter fw = null;
            try {
                fw = new FileWriter(StringUtils.joinWith(CommonConstant.DEFAULT_FILE_SEPARATOR, coordFileParentPath, layer + ".txt"), false);
                fw.write(result);
                fw.flush();
            } finally {
                if (null != fw) {
                    fw.close();
                }
            }
        }
    }

    // anno/yyyy/MM/dd/mask/nii/taskId/HHmmssSSS/mask.nii.gz
    private String genMaskOssPath(Integer taskId, String fileName) {
        Date date = new Date();
        String datePath = DateUtil.formatDate(date, "yyyy/MM/dd");
        String timePath = DateUtil.formatDate(date, "HHmmssSSS");
        return StringUtils.joinWith(CommonConstant.DEFAULT_FILE_SEPARATOR, "anno", datePath, "mask/nii", taskId.toString(), timePath, fileName);
    }
}
